package com.smart.community.commons.config;


import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;

/**
 * Redis配置类
 * 
 * 功能说明：
 * 1. 配置RedisTemplate用于直接操作Redis
 * 2. 支持Token存储、会话管理等基础功能
 * 3. 使用GenericJackson2JsonRedisSerializer确保序列化一致性
 * 4. 分离缓存序列化与接口序列化，确保类型安全
 * 
 * 注意：此配置类不再提供@Cacheable注解的缓存管理器支持
 * @Cacheable注解现在使用Caffeine本地缓存管理器
 * 
 * @author Wu.Liang
 * @version 4.0.0 - 移除缓存管理器，仅保留RedisTemplate
 * @since 2024-12-19
 * @updated 2025-01-30 - 移除Redis缓存管理器，改用Caffeine本地缓存
 */
@Configuration
public class RedisConfig {

	/**
	 * 配置Redis模板 - 使用GenericJackson2JsonRedisSerializer
	 * 
	 * 功能说明：
	 * 1. 用于直接操作Redis，如Token存储、会话管理等
	 * 2. 使用GenericJackson2JsonRedisSerializer确保序列化一致性
	 * 3. 支持复杂对象的存储和读取
	 * 4. 解决BigDecimal反序列化问题
	 * 
	 * @param connectionFactory Redis连接工厂
	 * @return Redis模板
	 */
	@Bean
	@ConditionalOnMissingBean
	public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
		RedisTemplate<String, Object> template = new RedisTemplate<>();
		template.setConnectionFactory(connectionFactory);

		// 设置key的序列化方式
		template.setKeySerializer(new StringRedisSerializer());
		template.setHashKeySerializer(new StringRedisSerializer());

		// 使用与缓存管理器相同的ObjectMapper配置
		com.fasterxml.jackson.databind.ObjectMapper objectMapper = createRedisObjectMapper();
		GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer(objectMapper);
		template.setValueSerializer(serializer);
		template.setHashValueSerializer(serializer);

		template.afterPropertiesSet();
		return template;
	}


	/**
	 * 配置接口返回JSON的序列化器（不含类型信息）
	 * 
	 * 注意：此配置仅影响接口返回，不影响缓存序列化 确保Controller返回给前端的JSON不含类型信息
	 * 
	 * @return MappingJackson2HttpMessageConverter
	 */
	@Bean
	@ConditionalOnMissingBean
	public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
		// 接口专用ObjectMapper：不保留类型信息
		com.fasterxml.jackson.databind.ObjectMapper objectMapper = new com.fasterxml.jackson.databind.ObjectMapper();

		// 重要：完全禁用所有类型信息注入，用于API响应序列化
		objectMapper.deactivateDefaultTyping();

		// 配置序列化特性
		objectMapper.configure(com.fasterxml.jackson.databind.SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
		objectMapper.configure(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
		objectMapper.configure(com.fasterxml.jackson.databind.SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
		objectMapper.configure(com.fasterxml.jackson.databind.SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);

		// 配置反序列化特性
		objectMapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
		objectMapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true);
		objectMapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.USE_BIG_INTEGER_FOR_INTS, true);
		objectMapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.READ_ENUMS_USING_TO_STRING, true);

		// 配置映射特性
		objectMapper.configure(com.fasterxml.jackson.databind.MapperFeature.USE_GETTERS_AS_SETTERS, false);
		objectMapper.configure(com.fasterxml.jackson.databind.MapperFeature.REQUIRE_SETTERS_FOR_GETTERS, false);
		objectMapper.configure(com.fasterxml.jackson.databind.MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORS, true);

		// 设置包含策略
		objectMapper.setSerializationInclusion(com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL);

		// 注册Java时间模块
		objectMapper.registerModule(new com.fasterxml.jackson.datatype.jsr310.JavaTimeModule());

		// 注册自定义模块
		objectMapper.registerModule(createCustomModule());

		MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
		converter.setObjectMapper(objectMapper);
		return converter;
	}

	/**
	 * 创建Redis专用的ObjectMapper
	 * 
	 * 解决BigDecimal反序列化问题：
	 * 使用ObjectMapper.DefaultTyping.NON_FINAL配置，让Jackson对JDK内置类型（如BigDecimal）自动识别，
	 * 无需@class类型信息，同时保留自定义POJO的类型信息
	 * 
	 * @return 配置好的ObjectMapper
	 */
	private com.fasterxml.jackson.databind.ObjectMapper createRedisObjectMapper() {
		// 1. 自定义ObjectMapper，解决内置类型反序列化问题
		com.fasterxml.jackson.databind.ObjectMapper objectMapper = new com.fasterxml.jackson.databind.ObjectMapper();
		
		// 注册Java 8时间模块
		objectMapper.registerModule(new com.fasterxml.jackson.datatype.jsr310.JavaTimeModule());
		
		// 配置类型检查：对所有类允许子类型，但内置类型无需@class
		objectMapper.activateDefaultTyping(
			com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator.instance,
			com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping.NON_FINAL // 非final类型需要类型信息（如自定义POJO）
			// NON_FINAL表示：final类型（如BigDecimal、String）无需类型信息，非final类型需要
		);
		
		// 配置序列化特性
		objectMapper.configure(com.fasterxml.jackson.databind.SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
		objectMapper.configure(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
		objectMapper.configure(com.fasterxml.jackson.databind.SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
		
		// 配置反序列化特性
		objectMapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
		objectMapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true);
		objectMapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.USE_BIG_INTEGER_FOR_INTS, true);
		objectMapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.READ_ENUMS_USING_TO_STRING, true);
		
		// 设置包含策略
		objectMapper.setSerializationInclusion(com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL);
		
		// 注册自定义模块
		objectMapper.registerModule(createCustomModule());
		
		return objectMapper;
	}

	/**
	 * 创建自定义模块
	 * 
	 * @return SimpleModule
	 */
	private com.fasterxml.jackson.databind.Module createCustomModule() {
		com.fasterxml.jackson.databind.module.SimpleModule customModule = new com.fasterxml.jackson.databind.module.SimpleModule();

		// 注册BigDecimal序列化器（支持类型信息）
		customModule.addSerializer(java.math.BigDecimal.class,
				new com.fasterxml.jackson.databind.ser.std.StdSerializer<java.math.BigDecimal>(
						java.math.BigDecimal.class) {
					@Override
					public void serialize(java.math.BigDecimal value, com.fasterxml.jackson.core.JsonGenerator gen,
							com.fasterxml.jackson.databind.SerializerProvider serializers) throws java.io.IOException {
						if (value != null) {
							gen.writeString(value.stripTrailingZeros().toPlainString());
						} else {
							gen.writeNull();
						}
					}
				});

		// 注册BigDecimal反序列化器
		customModule.addDeserializer(java.math.BigDecimal.class,
				new com.fasterxml.jackson.databind.deser.std.StdDeserializer<java.math.BigDecimal>(
						java.math.BigDecimal.class) {
					@Override
					public java.math.BigDecimal deserialize(com.fasterxml.jackson.core.JsonParser p,
							com.fasterxml.jackson.databind.DeserializationContext ctxt) throws java.io.IOException {
						String value = p.getValueAsString();
						return value != null ? new java.math.BigDecimal(value) : null;
					}
				});

		return customModule;
	}

}
